﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace LeRenard.Libraries.PlatformInspection.InfoNodes
{
    /// <summary>
    /// An object that contains information on a certain subject.    
    /// </summary>
    public class InfoNode : IInfoNode
    {
        #region Construction
        /// <summary>
        /// Intializes a new <see cref="InfoNode"/> object.
        /// </summary>
        /// <param name="name">The name of the <see cref="InfoNode"/>.</param>
        /// <param name="value">The value of the <see cref="InfoNode"/>.</param>
        /// <param name="innerInfoNodes">The additional inner <see cref="InfoNodes"/>.</param>
        /// <param name="displayStrategy">The <see cref="InfoNodeEmptyValueDisplayStrategy"/> when the <paramref name="value"/> is empty.</param>
        internal InfoNode(string name, string value = "", IEnumerable<InfoNode> innerInfoNodes = null, InfoNodeEmptyValueDisplayStrategy displayStrategy = InfoNodeEmptyValueDisplayStrategy.TreatAsNormalInfoNode)
        {
            ThrowIf.NullOrEmpty(() => name);

            _name = name;
            _value = value;

            if (_innerInfoNodes == null)
                _innerInfoNodes = new List<InfoNode>();
            if (innerInfoNodes != null)
                _innerInfoNodes.AddRange(innerInfoNodes);

            _displayStartegy = displayStrategy;
        }
        #endregion

        #region IInfoNode
        /// <summary>
        /// Gets the <see cref="InfoNodeEmptyValueDisplayStrategy"/> when the <see cref="Value"/> is empty or null.
        /// </summary>
        public InfoNodeEmptyValueDisplayStrategy DisplayStrategy { get { return _displayStartegy; } }
        private InfoNodeEmptyValueDisplayStrategy _displayStartegy;

        /// <summary>
        /// Gets the inner (underlying) <see cref="InfoNode"/>s, if there are <see cref="InfoNode"/>s available.
        /// </summary>
        public IEnumerable<InfoNode> InnerInfoNodes { get { return _innerInfoNodes; } }
        private List<InfoNode> _innerInfoNodes;

        /// <summary>
        /// Adds an <see cref="InfoNode"/> to this <see cref="InfoNode"/>.
        /// </summary>
        /// <param name="infoNode"></param>
        internal void AddInfoNode(InfoNode infoNode)
        {            
            _innerInfoNodes.Add(infoNode);
        }

        /// <summary>
        /// Adds an info node to this info node's <see cref="InnerInfoNodes"/>.
        /// </summary>        
        internal void AddInfoNode(string name, string value = "", IEnumerable<InfoNode> innerInfoNodes = null, InfoNodeEmptyValueDisplayStrategy displayStrategy = InfoNodeEmptyValueDisplayStrategy.TreatAsTitleInfoNode)
        {
            var infoNode = new InfoNode(name, value, innerInfoNodes, displayStrategy);
            AddInfoNode(infoNode);
        }        

        /// <summary>
        /// Adds multiple <see cref="InfoNode"/>s to this <see cref="InfoNode"/>.
        /// </summary>
        /// <param name="infoNodes"></param>
        internal void AddInfoNodes(IEnumerable<InfoNode> infoNodes)
        {
            _innerInfoNodes.AddRange(infoNodes);
        }

        /// <summary>
        /// Determines whether this <see cref="InfoNode"/> has any <see cref="InnerInfoNodes"/>.
        /// </summary>
        public bool HasInnerInfoNodes 
        {
            get
            {
                if (_innerInfoNodes == null)
                    return false;

                if (_innerInfoNodes.Count() == 0)
                    return false;

                return true;
            }
        }

        /// <summary>
        /// Gets the name (or title, subject) of the info the <see cref="InfoNode"/> provides.
        /// </summary>
        public string Name { get { return _name; } }
        public string _name;

        /// <summary>
        /// Gets the value of the <see cref="InfoNode"/>.
        /// </summary>
        public string Value { get { return _value; } }
        public string _value;

        /// <summary>
        /// Determines whether this <see cref="InfoNode"/> contains a <see cref="Value"/>.
        /// </summary>
        public bool HasValue 
        {
            get
            {
                if (_value == null)
                    return false;

                if (String.IsNullOrEmpty(_value))
                    return false;

                return true;
            }
        }
        #endregion        
    }
}
